package verda.kvantumo.Itala_Esperanta_Vortaro;

import android.content.Context;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;

/**
 * Kreas novan datumbazon, kien enmeti liston de vortoj kaj pozicioj
 * por la Itala Vortaro.
 * @author kvantumo
 *
 */
public class DBAdapter {
    public static final String KEY_V = "vorto";
    public static final String KEY_P = "pozicio";
    public static final String KEY_K = "koloro";
    public static final String KEY_L = "lit";
    public static final String KEY_I = "idx";
    private static final String TAG = "DBAdapter";
    private static final String DATABASE_NAME = "indekso.db";
    private static final String DATABASE_MAIN_TABLE = "indekso";
    private static final String DATABASE_INDEKSO_TABLE = "literoj";
    private static final int DATABASE_VERSION = 1;
    private static final String DATABASE_CREATE1 = "create table indekso ("+KEY_V+" text not null, "+KEY_P+" integer not null, "+KEY_K+" text non null);";
    private static final String DATABASE_CREATE2 = "create table literoj ("+KEY_L+" text not null PRIMARY KEY, "+KEY_I+" integer not null);";
    private final Context context;
    private DatabaseHelper DBHelper;
    private SQLiteDatabase db;
    private int countDB;
    
    public DBAdapter(Context ctx)
    {
        this.context = ctx;
        DBHelper = new DatabaseHelper(context);
        
        db = DBHelper.getReadableDatabase();
        Cursor mCursor = db.query(DATABASE_MAIN_TABLE, new String[] {"Count(*)"}, null, null, null, null, null);
        if (mCursor != null) {
            mCursor.moveToFirst();
        }
   	   countDB = mCursor.getInt(0);
   	   DBHelper.close();
    }
    
    private static class DatabaseHelper extends SQLiteOpenHelper
    {
        DatabaseHelper(Context context)
        {
            super(context, DATABASE_NAME, null, DATABASE_VERSION);
        }
        @Override
        public void onCreate(SQLiteDatabase db)
        {
            try {
                db.execSQL(DATABASE_CREATE1);
                db.execSQL(DATABASE_CREATE2);
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        @Override
        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)
        {
            Log.w(TAG, "Upgrading database from version " + oldVersion + " to "
                    + newVersion + ", which will destroy all old data");
            db.execSQL("DROP TABLE IF EXISTS " + DATABASE_MAIN_TABLE);
            onCreate(db);
        }
    }
    
    /**
     * Malfermas la datumbazon.
     * @return
     * @throws SQLException
     */
    public DBAdapter open() throws SQLException
    {
        db = DBHelper.getReadableDatabase();
        return this;
    }
    /**
     * Fermas la datumbazon.
     */
    public void close()
    {
        DBHelper.close();
    }
    /**
     * Redonas la totalan nombron da elementoj en la datumbazo.
     * @return La nombro da elementoj de la DB.
     */
    public int nombroElementoj(){
    	return countDB;
    }
    /**
     * Akiras ĉion de la datumbazo.
     * Redonas ambaŭ la kolonojn, kaj la vortoj kaj la pozicioj  
     * @return du kolojn, kie la unua estas la vorto kaj la dua la pozicio
     */
    public Cursor akirasCxiunVortojn()
    {
        return db.query(DATABASE_MAIN_TABLE, new String[] {KEY_V, KEY_P}, null, null, null, null, null);
    }
    /**
     * Egalas al akiri ĉion de la datumbazo.
     * {@link #getAllVortoj()}
     * @return du kolojn, kie la unua estas la vorto kaj la dua la pozicio
     */
    public Cursor getVortlisto()
    {
    	Cursor mCursor =
                db.query(true, DATABASE_MAIN_TABLE, new String[] {KEY_V, KEY_P}, null, null,
                null, null, null, null);
        if (mCursor != null) {
            mCursor.moveToFirst();
        }
        return mCursor;
    }
    /** Akiras la tutan indekson de la datumbazon.
    * @return du kolojn, kie la unua estas la literoj kaj la dua estas rowid de la unua vorto,
    * kiu komencas per tiuj literoj.
    */
   public Cursor akirasIndekson()
   {
       Cursor mCursor = db.query(DATABASE_INDEKSO_TABLE, new String[] {KEY_L, KEY_I}, null, null, null, null, null);
       if (mCursor != null) {
           mCursor.moveToFirst();
       }
       return mCursor;
   }
    /**
     * Akiras la valorojn de ĉiuj kolonoj por la pasita vorto.
     * @param vorto kies valorojn oni volas 
     * @return du kolojn, kie la unua estas la vorto kaj la dua la pozicio
     * @throws SQLException
     */
    public Cursor akirasVorton(String vorto) throws SQLException
    {
        Cursor mCursor =
                db.query(true, DATABASE_MAIN_TABLE, new String[] {KEY_V, KEY_P}, KEY_V + "=" + vorto, null,
                null, null, null, null);
        if (mCursor != null) {
            mCursor.moveToFirst();
        }
        return mCursor;
    }
    /**
     * Akiras la pozicion de la provizita vorto
     * @param vorto kies pozicion en la dosiero oni volas scii
     * @return entjero kun la pozicio
     * @throws SQLException
     */
    public int akirasPozicion(String vorto) throws SQLException
    {
        Cursor mCursor =
                db.query(true, DATABASE_MAIN_TABLE, new String[] {KEY_P}, String.format("%s = \'%s\'", KEY_V, vorto), null,
                null, null, null, null);
        if (mCursor != null) {
            mCursor.moveToFirst();
            if(mCursor.getCount() != 0)
         	   return mCursor.getInt(0);
            else return -1;
        }
        else return -1;
    }
    /** Akiras la valorojn de ĉiuj kolonoj por la pasita vorto.
    * @param vorto kies valorojn oni volas 
    * @return du kolojn, kie la unua estas la vorto kaj la dua la pozicio
    * @throws SQLException
    */
   public Cursor akirasLiteron(char litero) throws SQLException
   {
       Cursor mCursor =
               db.query(true, DATABASE_MAIN_TABLE, new String[] {KEY_V, KEY_P}, "(" + KEY_V + " LIKE \"" + litero + "%\")", null,
               null, null, null, null);
       if (mCursor != null) {
           mCursor.moveToFirst();
       }
       return mCursor;
   }
   
   /**
    * Akiras intervalon da datenoj de la ĉefa tabelo.
    * Rimarku: la rowid en la datumbazo startas de 1.
    * Tiu ĉi metodo, anstataŭe, permesas parti de 0 kiel normala vektora indekso.
    * @param starto la starta indekso (inkluzivita)
    * @param fino la fina indekso (ekskludita)
    * @return kursoron kun la rezultoj
    */
   public Cursor akirasIntervalon(int starto, int fino){
	   starto += 1;
	   fino += 1;
	   Cursor mCursor =
               db.query(true, DATABASE_MAIN_TABLE, new String[] {KEY_V, KEY_P, KEY_K},
            		   String.format("rowid >= %d AND rowid <= %s", starto, fino), null,
            		   null, null, null, null);
       if (mCursor != null)
           mCursor.moveToFirst();
       return mCursor;
   }
   
   /**
    * Akiras la vorton kun la responda indekso
    * @param indekso la indekso de la legenda vorto
    * @return la vorto, kies indekso estas tiu pasita
    */
   public String akirasVortonElID(int indekso){
	   return vID(indekso);
   }
   
   /**
    * Akiras la vorton kun la responda indekso
    * @param indekso la indekso de la legenda vorto
    * @return la vorto, kies indekso estas tiu pasita
    */
   public String vID(int indekso){
	   Cursor mCursor =
               db.query(true, DATABASE_MAIN_TABLE, new String[] {KEY_V}, String.format("rowid=%d", indekso), null,
               null, null, null, null);
       if (mCursor != null) {
           if(mCursor.moveToFirst())
        	   return mCursor.getString(0);
           else return "";
       }
       else return "";
   }
   
   /**
    * Akiras la rowid de la specifita vorto.
    * @param vorto la vorto, kies indekson oni volas koni.
    * @return integer kun la serĉita indekso; redonas -1 se nenio estis trovita.
    */
   public int akirasID(String vorto){
	   Cursor mCursor =
               db.query(true, DATABASE_MAIN_TABLE, new String[] {"rowid"}, String.format("vorto LIKE \'%s%%\' LIMIT 1", vorto), null,
               null, null, null, null);
       if (mCursor != null) {
           mCursor.moveToFirst();
       }
       if(!mCursor.isNull(0))
    	   return mCursor.getInt(0);
       else return -1;
   }
   
   /**
    * Akiras la rowid de la specifita vorto, komencante la serĉadon
    * de startIndekso. Kompare al {@link #akirasID(String)} tiu ĉi metodo
    * estas pli rapida, ĉar ĝi evitas la legado de la tuta datumbazo.
    * @param vorto la vorto, kies indekson oni volas koni.
    * @param startIndekso la indekso de kie komenci la serĉardo
    * @return integer kun la serĉita indekso; redonas -1 se nenio estis trovita.
    */
   public int akirasID(String vorto, int startIndekso){
	   Cursor mCursor =
               db.query(true, DATABASE_MAIN_TABLE, new String[] {"rowid"}, String.format("vorto LIKE \'%s%%\' AND rowid >= %d LIMIT 1", vorto, startIndekso), null,
               null, null, null, null);
       if (mCursor != null) {
           mCursor.moveToFirst();
           if(mCursor.getCount() != 0)
        	   return mCursor.getInt(0);
           else return -1;
       }
       else return -1;
   }
   
  /** 
   * Akiras la rowid de la specifita vorto per la metodo de dusekcado.
   * @param vorto la vorto, kies indekson oni volas koni.
   * @return integer kun la serĉita indekso; redonas -1 se nenio estis trovita.
   */
  public int trovasID_dusekcado(String nova, int starto){
      int j, ju, jm, j1;
      int n = countDB;
      boolean ascnd = true;
      boolean b;
      String s;
      if(starto < 0) return -1;
      j1 = starto;	// startas de 0 ĉar la datumbaza indekso startas de 1
      ju = n;
      while(ju - j1 > 1){
    	  jm = (ju+j1) >> 1;
    	  s = vID(jm);
    	  if(s == "") return -1;
    	  if(nova.compareToIgnoreCase(s) >= 0)
    		  b = true;
    	  else
    		  b = false;
    	  if(b == ascnd)
    		  j1 = jm;
    	  else
    		  ju = jm;
      }
      if(nova.equals(vID(0))) 
    	  j = 0;
      else if(nova.equals(vID(n-1)))
    	  j = n-2;
      else
    	  j = j1;

      return j;
  }
}
